#pragma once 


#include <iostream>
#include <string>
#include <cstring>
#include <functional>
#include <memory>
#include <unordered_map>
#include "sock.hpp"
#include "comm.hpp"
#include "epoller.hpp"
#include "log.hpp"
#include "nocopy.hpp"

class Connection;
class TcpServer;


const int Max_Num = 1024;
const int Max_Num_Wait_Num = 64;

const uint32_t EPOLL_IN = EPOLLIN | EPOLLET;
const uint32_t EPOLL_OUT = EPOLLOUT | EPOLLET;

typedef std::function<void(std::weak_ptr<Connection>)> func_t;

class Connection
{
public:
    Connection(int sockfd, const std::string& ip, uint16_t port)
        : _sockfd(sockfd)
        , _ip(ip)
        , _port(port)
    {

    }

    void SetHandler(func_t read_cb, func_t write_cb, func_t except_cb)
    {
        _read_cb = read_cb;
        _write_cb = write_cb;
        _except_cb = except_cb;
    }

    std::string& GetInbuffer()
    {
        return inbuffer;
    } 

    std::string& GetOutbuffer()
    {
        return outbuffer;
    } 

    int GetSockfd()
    {
        return _sockfd;
    }

    void AppendInbuffer(const std::string& str)
    {
        inbuffer += str;
    }

    void AppendOutbuffer(const std::string& str)
    {
        outbuffer += str;
    }

    void Print()
    {
        std::cout << inbuffer << std::endl;
    }

    void SetWeakptr(std::shared_ptr<TcpServer> tcp_server_ptr)
    {
        _cb_tcp_server = tcp_server_ptr;
    }
private:
    int _sockfd;

    // 缓冲区
    std::string inbuffer;
    std::string outbuffer;

public:
    func_t _read_cb;
    func_t _write_cb;
    func_t _except_cb;

    std::string _ip;
    uint16_t _port;

    // 回调指针
    // std::shared_ptr<class TcpServer> _cb_tcp_server;
    std::weak_ptr<class TcpServer> _cb_tcp_server;
};


// enable_shared_from_this 可以提供返回当前对象的this对应的shared_ptr
class TcpServer : public std::enable_shared_from_this<TcpServer>, NoCopy
{
public:
    TcpServer(uint16_t port, func_t on_message)
        : _port(port)
        , _listen_ptr(new Sock)
        , _epoll_ptr(new Epoller)
        , _on_message(on_message)
    {}

    ~TcpServer()
    {

    }

    void ServerInit()
    {
        _listen_ptr->Socket();
        SetNonBlock(_listen_ptr->GetSockfd());
        _listen_ptr->Bind(_port);
        _listen_ptr->Listen();
        
        AddConnection(_listen_ptr->GetSockfd(), EPOLL_IN,
            std::bind(&TcpServer::Acceptor, this, std::placeholders::_1),
            nullptr, nullptr, "0.0.0.0", 0);

        lg(Info, "listen sock : %d 创建完成", _listen_ptr->GetSockfd());
    }
    
    void AddConnection(int fd, int events, func_t read_cb, func_t write_cb, func_t except_cb, const std::string& ip, uint16_t port)
    {
        // 建立新的Connection 节点

        std::shared_ptr<Connection> newnode(new Connection(fd, ip, port));

        // 那么 TcpServer 类的对象必须是通过 std::shared_ptr<TcpServer> 来创建和管理的
        newnode->SetWeakptr(shared_from_this());   // 返回当前对象的share_ptr

        newnode->SetHandler(read_cb, write_cb, except_cb);
        // 加入epoll中
        _epoll_ptr->EpollUpdate(EPOLL_CTL_ADD, fd, events);

        //插入 _connections
        _connections.insert({ fd, newnode });
    }


    // 连接管理器
    void Acceptor(std::weak_ptr<Connection> conn)
    {
        auto connection = conn.lock();
        int listen_sock = connection->GetSockfd();
        while(true)
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            // 捕捉链接
            int sock = ::accept(listen_sock, (struct sockaddr*)(&peer), &len);
            if(sock > 0)
            {
                // 获取client ip 和  port
                uint16_t client_port = ntohs(peer.sin_port);
                char client_ip_buffer[128];
                inet_ntop(AF_INET, &peer.sin_addr.s_addr, client_ip_buffer, sizeof(client_ip_buffer));
                
                // 将文件描述符设置为非阻塞的
                SetNonBlock(sock);

                // 将新链接添加到 _connection 中
                AddConnection(sock, EPOLL_IN, 
                std::bind(&TcpServer::Recver, this, std::placeholders::_1),
                std::bind(&TcpServer::Sender, this, std::placeholders::_1),
                std::bind(&TcpServer::Expector, this, std::placeholders::_1),
                client_ip_buffer, client_port);

                PrintSockfd(); // debug
            }
            else
            {
                if(errno == EWOULDBLOCK)  // 非阻塞 没有链接了 读完了
                    break;
                else if(errno == EINTR)   // 信号中断了
                    continue;
                else                      // 真出错了
                    return;
            }
        }

    }


    // 事件管理器
    void Recver(std::weak_ptr<Connection> conn)
    {
        if(conn.expired())
            return; 
        auto connection = conn.lock();

        char buffer[1024];
        while(1)
        {
            memset(buffer, 0, sizeof(buffer));

            // 读取数据
            ssize_t n = recv(connection->GetSockfd(), buffer, sizeof(buffer), 0);
            if(n > 0)
            {
                connection->AppendInbuffer(buffer);
                connection->Print();
            }
            else if(n == 0)
            {
                // 读完了
                lg(Info, "sockfd : %d, client info %s : %d quit...",connection->GetSockfd(), connection->_ip.c_str(), connection->_port);
                connection->_except_cb(connection);
                break;
            }
            else
            {
                // 出错了
                if(errno == EWOULDBLOCK)  // 没有读到数据（非阻塞）
                    break;
                else if(errno == EINTR)   // 被异常打断了
                    continue;
                else                      // 读取真出错了
                {
                    lg(Warning, "sockfd : %d, client info %s : %d recv error...",connection->GetSockfd(), connection->_ip.c_str(), connection->_port);
                    connection->_except_cb(connection);
                    return;
                }
            }
        }

        _on_message(connection);
    }

    void EnableRW(int sockfd, bool flag_read, bool flag_write)
    {
        uint32_t events = 0;
        events |= (flag_read ? EPOLLIN : 0);
        events |= (flag_write ? EPOLLOUT : 0);

        // 更改对应的 关注事项
        _epoll_ptr->EpollUpdate(EPOLL_CTL_MOD, sockfd, events);
    }

    void Sender(std::weak_ptr<Connection> conn)
    {
        if(conn.expired())
            return; 
        auto connection = conn.lock();
        std::string& out_str = connection->GetOutbuffer();
        while(1)
        {
            ssize_t n = send(connection->GetSockfd(), out_str.c_str(), out_str.size(), 0);
            if(n > 0)
            {
                out_str.erase(0, n);
                if(out_str.empty())
                    break;
            }
            else if(n == 0)
            {
                // 发完了
                return;
            }
            else
            {
                // 出错了
                if(errno == EWOULDBLOCK) // 对方接受缓冲区不够了
                    break;
                else if(errno == EINTR)  // 被异常打断了
                    continue;
                else                     // 发送真出错了
                {
                    lg(Warning, "sockfd : %d, client info %s : %d send error...",connection->GetSockfd(), connection->_ip.c_str(), connection->_port);
                    connection->_except_cb(connection);
                    return;
                }
            }
        }

        if(out_str.empty())
        {
            // 关闭 读 关心
            EnableRW(connection->GetSockfd(), true, false);
        }
        else
        {
            // 设置 读 关心
            EnableRW(connection->GetSockfd(), true, true);
        }
    }

    void Expector(std::weak_ptr<Connection> conn)
    {
        if(conn.expired())
            return; 
        auto connection = conn.lock();
        
        // std::cout << "处理异常" << std::endl;
        int sockfd = connection->GetSockfd();

        if(IsConnectionSafe(sockfd) == 0)
            return; 
            
        // 1, 移除对特定fd的关心
        _epoll_ptr->EpollUpdate(EPOLL_CTL_DEL, sockfd, 0);

        // 2, 关闭文件描述符
        close(sockfd);

        // 3, 删除对应的connect节点
        _connections.erase(sockfd);

        lg(Info, "已删除异常的文件描述符sockfd %d 的相关信息", sockfd);
    }

    bool IsConnectionSafe(int sockfd)
    {
        return _connections.count(sockfd);
    }

    void PrintSockfd()
    {
        std::cout << "已连接的文件描述符 : ";
        for(auto& ch : _connections)
        {
            std::cout << ch.first << " ";
        }
        std::cout << std::endl;
    }

    void Dispatcher(int timeout)
    {
        struct epoll_event recv[Max_Num];
        int n = _epoll_ptr->EpollWait(recv, Max_Num_Wait_Num, timeout);
        if(n > 0)
        {
            for(int i = 0; i < n; i++)
            {
                int fd = recv[i].data.fd;
                uint32_t events = recv[i].events;


                // 统一把异常转化为读写异常
                // if(events & EPOLLERR)
                //     events |= (EPOLLIN | EPOLLOUT);
                // if(events & EPOLLHUP)
                //      events |= (EPOLLIN | EPOLLOUT);

                if((events & EPOLLIN) && IsConnectionSafe(fd))
                {
                    if(_connections[fd]->_read_cb)
                        _connections[fd]->_read_cb(_connections[fd]);
                }
                if((events & EPOLLOUT) && IsConnectionSafe(fd))
                {
                    if(_connections[fd]->_write_cb)
                        _connections[fd]->_write_cb(_connections[fd]);
                }

            }
        }
    }

    void Run()
    {
        while(1)
        {
            Dispatcher(1000);
        }
    }

private:
    std::shared_ptr<Sock> _listen_ptr;
    std::shared_ptr<Epoller> _epoll_ptr;
    uint16_t _port;
    std::unordered_map<int, std::shared_ptr<Connection>> _connections;

    func_t _on_message;
};